const parser = require('fast-xml-parser');
const fs = require('fs');

/**
 * {
 *  pname:"",
 *  name:"",
 * }
 */
let classParent = [

];

let nodeChilds = JSON.parse(fs.readFileSync("./keys/nodes.json", "utf-8"))


function xml2json(fileName) {
    fs.readFile(fileName, "utf-8", (err, con) => {
        if (err) {
            console.log("err", err);
            return;
        }

        let data = parser.parse(con, {
            ignoreAttributes: false,
            attributeNamePrefix: "",
            allowBooleanAttributes: true
        })

        xmlInherits(data);
        nodesProp(fileName, data);
        jsonFile(fileName, data);
    })
}

// node
function nodesProp(fileName, jsonData, isComment = false) {
    let c = jsonData.class
    let nodeProps = [];
    if (c.inherits && nodeChilds.indexOf(c.name) > -1 && c.members) {
        if (!Array.isArray(c.members.member)) {
            c.members.member = [c.members.member]
        }
        c.members.member.forEach(m => {
            nodeProps.push({
                "name": `${m.name}`,
                "type": m.type,
                "default": m.default,
                "comment": isComment ? m["#text"] : "",
            })
        })

        fs.writeFile(
            fileName.replace("./xml", "./nodes").replace(".xml", ".json"),
            JSON.stringify({ "parent": c.inherits, "name": c.name, props: nodeProps }, "", 2),
            (err) => {
                console.log(fileName, "nodes ok")
            }
        )
    }
}
/**
 * key的修正
 * /**
 * {
 *      "className":{
 *          "name":"",
 *          "parent":"",
 *          "comment":"",
 *          "des":"",
 *          "const":[
 *              "title":"",  //title
 *              "kv":""   //key=value
 *          ],
 *          enums:[
 *              "name"
 *              "value" [
 *                  {
 *                      "key",
 *                      "comment"
 *                  }
 *              ]
 *          ]
 *          "props":[
 *              "prop":"" ,//name:type = default,
 *              "setget":true, true/false
 *              "comment":"",     
 *          ],
 *          "setget":[
 *              "set_name",
 *              "get_name"
 *          ]
 *          "methods":[
 *              "fun":"",//qualifier funcName(..argType:argName):returnType
 *              "comment":""
 *          ]
 *      }
 * }
 *
 * @param {*} jsonData 
 */
function xmlKey(jsonData, isComment = false) {
    let c = jsonData.class
    // console.log("c", JSON.stringify(c, "", 2))
    //处理字段
    let result = {
        name: c.name,
        parent: c.inherits
            ? c.inherits
            : "Top",
        comment: c.brief_description,
        des: isComment ? c.description
            .replace("\n", "")
            .replace("\t", "") : '',
        const: [],
        enums: [],
        props: [],
        setters: [],
        getters: [],
        methods: [],
        signals: []
    }
    //const
    if (c.constants) {
        if (!Array.isArray(c.constants.constant)) {
            c.constants.constant = [c.constants.constant]
        }
        c.constants.constant.forEach(e => {
            //enum
            if (e.enum) {
                let check = result.enums
                    .find(d => d.name == e.enum)
                if (check) {
                    if (isComment) {
                        check.value.push({
                            "key": `${e.name} = ${parseInt(e.value)}`,
                            "comment": isComment ? e["#text"] : ""
                        })
                    } else {
                        check.value.push({
                            "key": `${e.name} = ${parseInt(e.value)}`
                        })
                    }
                } else {
                    if (isComment) {
                        result.enums.push({
                            "name": e.enum,
                            "value": [
                                {
                                    "key": `${e.name} = ${parseInt(e.value)}`,
                                    "comment": isComment ? e["#text"] : ""
                                }
                            ]
                        })
                    } else {
                        result.enums.push({
                            "name": e.enum,
                            "value": [
                                {
                                    "key": `${e.name} = ${parseInt(e.value)}`
                                }
                            ]
                        })
                    }

                }
            } else {
                //普通常量
                if (isComment) {
                    result.const.push({
                        "name": `${e.name}`,
                        "value": `${e.value}`,
                        "comment": isComment ? e["#text"] : ""
                    })
                } else {
                    result.const.push({
                        "name": `${e.name}`,
                        "value": `${e.value}`
                    })
                }
            }
        })
    }
    //props setgets
    if (c.members) {
        if (!Array.isArray(c.members.member)) {
            c.members.member = [c.members.member]
        }
        c.members.member.forEach(m => {
            if (isComment) {
                result.props.push({
                    "name": `${m.name}`,
                    "prop": `${m.type} ${m.name}  ${m.default ? "= " + toNum(m.default) : ''}`,
                    "setget": `${m.getter || m.setter ? true : false}`,
                    "comment": isComment ? m["#text"] : ""
                })
            } else {
                result.props.push({
                    "name": `${m.name}`,
                    "prop": `${m.type} ${m.name}  ${m.default ? "= " + toNum(m.default) : ''}`,
                    "setget": `${m.getter || m.setter ? true : false}`
                })
            }
            if (m.setter) {
                result.setters.push(`${m.setter}(${m.type} value)`)
            }
            if (m.getter) {
                result.getters.push(`${m.type} ${m.getter}()`)
            }
        })
    }
    // methods
    if (c.methods) {
        if (!Array.isArray(c.methods.method)) {
            c.methods.method = [c.methods.method]
        }
        c.methods.method.forEach(m => {
            let args = []
            if (!!m.argument) {
                if (Array.isArray(m.argument)) {
                    m.argument.forEach(a => {
                        args.push(`${a.enum ? a.enum : a.type} ${a.name}${a.default ? "=" + a.default : ''}`)
                    })
                } else {
                    let a = m.argument;
                    args.push(`${a.type} ${a.name}`)
                }
            }
            if (isComment) {
                result.methods.push({
                    "name": `${m.name}`,
                    "fun": `${m.qualifiers ? m.qualifiers : ''} ${m["return"] ? m["return"]["type"] : ''} ${m.name}(${args.join(',')})`,
                    "comment": isComment ? m["description"] : "",
                })
            } else {
                result.methods.push({
                    "name": `${m.name}`,
                    "fun": `${m.qualifiers ? m.qualifiers : ''} ${m["return"] ? m["return"]["type"] : ''} ${m.name}(${args.join(',')})`
                })
            }
        })
    }
    // signals
    if (c.signals) {
        if (!Array.isArray(c.signals.signal)) {
            c.signals.signal = [c.signals.signal]
        }
        c.signals.signal.forEach(s => {
            let args = []
            if (!!s.argument) {
                if (Array.isArray(s.argument)) {
                    s.argument.forEach(a => {
                        args.push(`${a.enum ? a.enum : a.type} ${a.name}${a.default ? "=" + a.default : ''}`)
                    })
                } else {
                    let a = s.argument;
                    args.push(`${a.type} ${a.name}`)
                }
            }

            if (isComment) {
                result.signals.push({
                    "name": `${s.name}`,
                    "fun": `${s.name}(${args.join(',')})`,
                    "comment": `${s.description}`
                })
            } else {
                result.signals.push({
                    "name": `${s.name}`,
                    "fun": `${s.name}(${args.join(',')})`,
                })
            }
        })
    }
    return result;
}

function toNum(s) {
    return s;
}
function t() {
    let con = fs.readFileSync("./xml/classes/Color.xml", "utf-8");

    let j = parser.parse(con, {
        ignoreAttributes: false,
        attributeNamePrefix: "",
        allowBooleanAttributes: true
    })
    xmlKey(j);
}
// t();
/**
 * 生成继承树
 * @param {*} jsonData 
 */
function xmlInherits(jsonData) {
    let c = jsonData.class;
    if (c.inherits) {
        classParent.push({ pid: c.inherits, id: c.name })
    } else {
        classParent.push({ pid: "Top", id: c.name })
    }
}
/**
 * 生成继承树
 */
function tree() {
    let jsonString = fs.readFileSync("./keys/tree.json", "utf-8");
    let data = JSON.parse(jsonString);
    /**
     * {
        *  name:"",
        *  children:[]
     * }
     */

    function array2Tree(arr) {
        if (!Array.isArray(arr) || !arr.length) return;
        let map = {};
        arr.forEach(item => map[item.id] = item);

        let roots = [];
        arr.forEach(item => {
            const parent = map[item.pid];
            if (parent) {
                (parent.children || (parent.children = [])).push(item);
            }
            else {
                roots.push(item);
            }
        })
        return roots;
    }

    let r = array2Tree(data);
    fs.writeFileSync("./keys/p.json", JSON.stringify(r, "", 2))
    fs.writeFileSync("./keys/ele-tree.json", JSON.stringify(r))
}
function jsonFile(fileName, jsonData) {
    fs.writeFile(
        fileName.replace("./xml", "./api/").replace(".xml", ".json").toLocaleLowerCase(),
        JSON.stringify(xmlKey(jsonData)),
        (err) => {
            console.log(fileName, "json ok")
        }
    )
}

// xmlHandle();

function parseDir(dir) {
    fs.readdir(dir, (err, data) => {
        data.forEach(f => {
            if (f != ".empty") {
                fs.stat(dir + "/" + f, (err, stat) => {
                    if (stat.isFile()) {
                        xml2json(dir + "/" + f)
                    } else {
                        parseDir(dir + "/" + f)
                    }
                })
            }
        })
    })

    setTimeout(() => {
        // console.log("tree", classParent)
        let result = {};
        classParent.forEach(e => {
            result[e.id] = [];
        })

        Object.keys(result).forEach(p => {
            let childs = classParent.filter(c => c.pid == p)
                .map(c => c.id);
            result[p] = childs
        })

        // 收集node
        // {}
        let nodes = [];
        // {label:"",children:[{label:"",children:[{},{}]}]}
        let labels = [];
        //查找Node的子节点
        classParent.forEach(e => {
            if (e.pid == "Node" || e.id == "Node") {
                getChild(e.id);
            }
        })

        function getChild(p) {
            // 当前节点
            nodes.push(p);
            let cs = classParent.filter(c => c.pid == p)
                .map(c => c.id);

            if (cs.length > 0) {
                // 子节点
                nodes = nodes.concat(cs);

                cs.forEach(c => {
                    getChild(c);
                })
            }
        }

        // 获取Node
        fs.writeFileSync("./keys/tree.json", JSON.stringify(classParent))
        console.log("tree", "ok")
        fs.writeFileSync("./keys/childs.json", JSON.stringify(result))
        console.log("childs", "ok")
        fs.writeFileSync("./keys/nodes.json", JSON.stringify(nodes))
        console.log("nodes", "ok")

    }, 3000)
}

parseDir("./xml")
tree();

